package cn.micro.keep.accounts.auth;

import cn.hutool.core.util.StrUtil;

import cn.micro.keep.accounts.api.ResponseEnum;
import cn.micro.keep.accounts.common.constant.SecurityConstants;
import cn.micro.keep.accounts.common.utils.RequestUtils;
import cn.micro.keep.accounts.common.utils.ResponseUtils;
import cn.micro.keep.accounts.config.IgnoreUrlsConfig;
import io.jsonwebtoken.Claims;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * JWT 校验过滤器
 *
 * @author haoxr
 * @since 2022/10/1
 */
public class JwtAuthenticationFilter extends OncePerRequestFilter {


    private final JwtTokenManager tokenManager;

    private final IgnoreUrlsConfig ignoreUrlsConfig;


    public JwtAuthenticationFilter(JwtTokenManager tokenManager, IgnoreUrlsConfig ignoreUrlsConfig) {
        this.tokenManager = tokenManager;
        this.ignoreUrlsConfig = ignoreUrlsConfig;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        //对白名单路径直接放行
        String requestURI = request.getRequestURI();
        //路径匹配
        if (ignoreUrlsConfig.getUrls().stream().anyMatch(requestURI::contains)) {
            //移除请求头授权信息
            request.removeAttribute(SecurityConstants.TOKEN_KEY);
            chain.doFilter(request, response);
            return;
        }
        String jwt = RequestUtils.resolveToken(request);
        if (StrUtil.isNotBlank(jwt) && SecurityContextHolder.getContext().getAuthentication() == null) {
            try {
                // 解析&验证 JWT
                Claims claims = this.tokenManager.parseAndValidateToken(jwt);
                // JWT验证有效获取Authentication存入Security上下文
                Authentication authentication = this.tokenManager.getAuthentication(claims);
                SecurityContextHolder.getContext().setAuthentication(authentication);
                chain.doFilter(request, response);
            }catch (Exception e){
                ResponseUtils.writeErrMsg(response, ResponseEnum.UNAUTHORIZED);
            }
        }else{
            ResponseUtils.writeErrMsg(response, ResponseEnum.UNAUTHORIZED);
        }
    }
}
